package com.hardson.toolkit.swing.print;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;

import javax.swing.JComponent;

public class JComponentVista extends Vista implements Printable {

	private static final boolean SYMMETRIC_SCALING = true;

	private static final boolean ASYMMETRIC_SCALING = false;

	private double mScaleX;

	private double mScaleY;

	/**
	 * The Swing component to print.
	 */
	private JComponent mComponent;

	/**
	 * Create a Pageable that can print a Swing JComponent over multiple pages.
	 * 
	 * @param c
	 *            The swing JComponent to be printed.
	 * 
	 * @param format
	 *            The size of the pages over which the componenent will be
	 *            printed.
	 */
	public JComponentVista(final JComponent c, final PageFormat format) {

		this.setPageFormat(format);
		this.setPrintable(this);
		this.setComponent(c);
		/*
		 * Tell the Vista we subclassed the size of the canvas.
		 */
		Rectangle componentBounds = c.getBounds(null);
		this.setSize(componentBounds.width, componentBounds.height);
		this.setScale(1, 1);

	}

	protected void setComponent(final JComponent c) {
		this.mComponent = c;
	}

	protected void setScale(final double scaleX, final double scaleY) {
		this.mScaleX = scaleX;
		this.mScaleY = scaleY;
	}

	public void scaleToFitX() {
		PageFormat format = this.getPageFormat();
		Rectangle componentBounds = this.mComponent.getBounds(null);
		double scaleX = format.getImageableWidth() / componentBounds.width;
		double scaleY = scaleX;
		if (scaleX < 1) {
			this.setSize((float) format.getImageableWidth(),
					(float) (componentBounds.height * scaleY));
			this.setScale(scaleX, scaleY);
		}
	}

	public void scaleToFitY() {
		PageFormat format = this.getPageFormat();
		Rectangle componentBounds = this.mComponent.getBounds(null);
		double scaleY = format.getImageableHeight() / componentBounds.height;
		double scaleX = scaleY;
		if (scaleY < 1) {
			this.setSize((float) (componentBounds.width * scaleX),
					(float) format.getImageableHeight());
			this.setScale(scaleX, scaleY);
		}
	}

	public void scaleToFit(final boolean useSymmetricScaling) {
		PageFormat format = this.getPageFormat();
		Rectangle componentBounds = this.mComponent.getBounds(null);
		double scaleX = format.getImageableWidth() / componentBounds.width;
		double scaleY = format.getImageableHeight() / componentBounds.height;
		if (scaleX < 1 || scaleY < 1) {
			if (useSymmetricScaling) {
				if (scaleX < scaleY) {
					scaleY = scaleX;
				} else {
					scaleX = scaleY;
				}
			}
			this.setSize((float) (componentBounds.width * scaleX),
					(float) (componentBounds.height * scaleY));
			this.setScale(scaleX, scaleY);
		}
	}

	public int print(final Graphics graphics, final PageFormat pageFormat, final int pageIndex)
			throws PrinterException {
		Graphics2D g2 = (Graphics2D) graphics;
		g2.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
		Rectangle componentBounds = this.mComponent.getBounds(null);
		g2.translate(-componentBounds.x, -componentBounds.y);
		g2.scale(this.mScaleX, this.mScaleY);
		boolean wasBuffered = this.mComponent.isDoubleBuffered();
		this.mComponent.paint(g2);
		this.mComponent.setDoubleBuffered(wasBuffered);
		return PAGE_EXISTS;
	}

}
